package com.ruoyi.finance.livestreaming.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.github.pagehelper.util.StringUtil;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.finance.livestreaming.entity.*;
import com.ruoyi.finance.livestreaming.mapper.*;
import com.ruoyi.finance.livestreaming.service.IFiDigitalLivestreamingService;
import com.ruoyi.finance.livestreaming.vo.CounterChargeVO;
import com.ruoyi.finance.protal.utils.ImageToBase64Converter;
import com.ruoyi.finance.protal.utils.ShanDeCreateOrder;
import com.ruoyi.finance.protal.utils.ShanDeCreateOrderH5;
import com.ruoyi.finance.rules.entity.SzOtherRule;
import com.ruoyi.finance.rules.entity.SzPromotionTree;
import com.ruoyi.finance.rules.entity.SzUser;
import com.ruoyi.finance.rules.entity.SzVipRule;
import com.ruoyi.finance.rules.mapper.SzPromotionTreeMapper;
import com.ruoyi.finance.rules.mapper.SzUserMapper;
import com.ruoyi.finance.rules.task.SZRuleCache;
import com.ruoyi.module.utils.BigDecimalChain;
import com.ruoyi.pay.vo.PayVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 数字直播Service业务层处理
 *
 * @author wangmh
 * @date 2023-09-17
 */
@Slf4j
@Service
public class FiDigitalLivestreamingServiceImpl implements IFiDigitalLivestreamingService
{
    @Autowired
    private FiDigitalLivestreamingMapper fiDigitalLivestreamingMapper;

    @Autowired
    private SzUserMapper szUserMapper;

    @Autowired
    private SZRuleCache ruleCache;

    @Autowired
    private SzOrderMapper szOrderMapper;

    @Autowired
    private SzEnergyRecordMapper szEnergyRecordMapper;

    @Autowired
    private SzPromotionTreeMapper szPromotionTreeMapper;

    @Autowired
    private SzWalletDetailMapper szWalletDetailMapper;

    @Autowired
    private SzAwardRecordMapper szAwardRecordMapper;

    @Autowired
    private SzVipUpgradeRecordMapper szVipUpgradeRecordMapper;

    @Autowired
    private SzMutualPayRecordMapper szMutualPayRecordMapper;

    @Autowired
    private SzWithdrawalDetailMapper szWithdrawalDetailMapper;

    @Autowired
    private SzDeductionAmountRecordMapper szDeductionAmountRecordMapper;


    /**
     * 查询数字直播列表
     */
    @Override
    public List<SzUser> selectFiDigitalLivestreamingList(SzUser szUser) {
        return fiDigitalLivestreamingMapper.selectFiDigitalLivestreamingList(szUser);
    }


    /**
     * 购买数字人直播 没有邀请人
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult buyProduct(String userId) {
        return this.separateTopup(userId, "1", null) ? AjaxResult.success() : AjaxResult.error();
    }


    /**
     * 购买数字人直播 没有邀请人  抵扣支付
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult deductionBuyProduct(String userId, BigDecimal amount, BigDecimal deductionAmount) {
        return this.deductionSeparateTopup(userId, "1", null, amount, deductionAmount) ? AjaxResult.success() : AjaxResult.error();
    }


    /**
     * 购买数字人直播 有邀请人
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult buyProductByInvite(String userId, String parentId) {
        return this.inviteTopup(userId, parentId, "1", null) ? AjaxResult.success() : AjaxResult.error();
    }


    /**
     * 购买数字人直播 有邀请人  抵扣支付
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult deductionBuyProductByInvite(String userId, String parentId, BigDecimal amount, BigDecimal deductionAmount) {
        return this.deductionInviteTopup(userId, parentId, "1", null, amount, deductionAmount) ? AjaxResult.success() : AjaxResult.error();
    }


    /**
     * 数字直播对冲
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult mutualRecharge(String fromUser, String toUser) {
        if (fromUser.equals(toUser)){
            return AjaxResult.error("不能给同一账号对冲");
        }

        SzOtherRule otherRule = ruleCache.getOtherRule();
        SzUser user = szUserMapper.selectById(fromUser);

        if (user.getDeductionAmount().compareTo(BigDecimal.ZERO) != 0){
            return AjaxResult.error(user.getNickname() + "非正常用户，完成还款后可正常对冲");
        }

        if (BigDecimalChain.chain(user.getSzWithdrawalBalance()).sub(user.getFrozenAccount()).get().compareTo(otherRule.getPricing()) < 0){
            return AjaxResult.error(user.getNickname() + "可提现余额不足" + otherRule.getPricing());
        }

        if (user.getSzEnergy().compareTo(otherRule.getPricing()) < 0){
            return AjaxResult.error(user.getNickname() + "能量值不足" + otherRule.getPricing());
        }

        this.deductBalanceOfTopup(fromUser, toUser);

        List<SzPromotionTree> szPromotionTrees = szPromotionTreeMapper.selectList(new LambdaQueryWrapper<SzPromotionTree>().eq(SzPromotionTree::getUserId, toUser));
        if (CollectionUtils.isEmpty(szPromotionTrees)){
            // 没有推荐人
            return this.separateTopup(toUser, "6", null) ? AjaxResult.success() : AjaxResult.error();
        }else{
            return this.inviteTopup(toUser, szPromotionTrees.get(0).getParentId().toString(), "6", null) ? AjaxResult.success() : AjaxResult.error();
        }
    }

    /**
     * 数字直播对冲
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult mutualRechargeFree(CounterChargeVO vo) {
        if (vo.getFromUser().equals(vo.getToUser())){
            return AjaxResult.error("不能给同一账号对冲");
        }

        SzUser user = szUserMapper.selectById(vo.getFromUser());

        if (user.getDeductionAmount().compareTo(BigDecimal.ZERO) != 0){
            return AjaxResult.error(user.getNickname() + "非正常用户，完成还款后可正常对冲");
        }

        if (BigDecimalChain.chain(user.getSzWithdrawalBalance()).sub(user.getFrozenAccount()).get().compareTo(vo.getPricing()) < 0){
            return AjaxResult.error(user.getNickname() + "可提现余额不足" + vo.getPricing());
        }

        if (user.getSzEnergy().compareTo(vo.getPricing()) < 0){
            return AjaxResult.error(user.getNickname() + "能量值不足" + vo.getPricing());
        }

        this.deductBalanceOfTopupFree(vo);

        List<SzPromotionTree> szPromotionTrees = szPromotionTreeMapper.selectList(new LambdaQueryWrapper<SzPromotionTree>().eq(SzPromotionTree::getUserId, vo.getToUser()));
        if (CollectionUtils.isEmpty(szPromotionTrees)){
            // 没有推荐人
            return this.separateTopupFree(vo.getToUser(), "6", null,vo) ? AjaxResult.success() : AjaxResult.error();
        }else{
            return this.inviteTopupFree(vo.getToUser(), szPromotionTrees.get(0).getParentId().toString(), "6", null,vo) ? AjaxResult.success() : AjaxResult.error();
        }
    }

    @Override
    public AjaxResult frozenOrEnable(Long id, String type) {
        if (StringUtil.isEmpty(type) && !type.equals("1") && !type.equals("2") && id == null && id == 0L){
            return AjaxResult.error();
        }
        com.ruoyi.finance.rules.entity.SzUser user = szUserMapper.selectById(id);
        user.setIsFrozen(type);
        if (type.equals("1")){
            user.setFrozenTime(LocalDateTime.now());
        }
        szUserMapper.updateById(user);
        return AjaxResult.success();
    }

    /**
     * 充值，不购买产品
     */
    @Override
    public void topUp(SzOrder order) {
        //    购买方 余额为充值金额
        SzUser szUser = szUserMapper.selectById(order.getUserId());
        szUser.setSzWithdrawalBalance(order.getRechargeAmount());
        szUserMapper.updateById(szUser);
    }



    /**
     * 获取数字直播用户邀请人
     */
    @Override
    public List<SzPromotionTree> userInviteTree(Long userId) {
        List<SzPromotionTree> userList = buildTree(szUserMapper.getUserInviteTree(userId), userId);
        userList.forEach(this::calculateTotalAmount);
        return userList;
    }

    /**
     * 数字直播 购买记录查询
     */
    @Override
    public Map<String, Object> purchaseRecord(Long userId) {
        if (userId == null){
            return null;
        }

        Map<String, Object> data = new LinkedHashMap<>();
        List<Map<String, Object>> list = fiDigitalLivestreamingMapper.purchaseRecord(userId);
        data.put("list", list);
        return data;
    }


    /**
     * 用户余额细明
     */
    @Override
    public Map<String, Object> balanceDetailAdmin(Long userId) {
        if (userId == null){
            return null;
        }

        List<Map<String, Object>> list = fiDigitalLivestreamingMapper.balanceDetailAdmin(userId);
        Map<String, BigDecimal> amount = fiDigitalLivestreamingMapper.getUserWalletAmount(userId);

        Map<String, Object> data = new LinkedHashMap<>();
        data.put("list", list);
        data.put("amount", amount);
        return data;
    }

    @Override
    public Map<String, Object> withdrawalBalance(Long userId) {
        if (userId == null){
            return null;
        }

        List<Map<String, Object>> list = fiDigitalLivestreamingMapper.withdrawalBalance(userId);
        Map<String, BigDecimal> amount = fiDigitalLivestreamingMapper.getUserWalletBalanceAmount(userId);

        Map<String, Object> data = new LinkedHashMap<>();
        data.put("list", list);
        data.put("amount", amount);
        return data;
    }

    @Override
    public AjaxResult createOrder(String userId, String parentId) {
        SzOtherRule otherRule = ruleCache.getOtherRule();
        SzUser user = szUserMapper.selectById(userId);
        log.info("管理端，扫码支付    开始保存订单");

        if (StringUtil.isNotEmpty(parentId)){
            if (szPromotionTreeMapper.selectCount(new LambdaQueryWrapper<SzPromotionTree>().eq(SzPromotionTree::getUserId, userId)) ==0 ){
                SzPromotionTree promotionTree = new SzPromotionTree();
                promotionTree.setUserId(Long.parseLong(userId));
                promotionTree.setParentId(Long.parseLong(parentId));
                promotionTree.setCreateTime(LocalDateTime.now());
                szPromotionTreeMapper.insert(promotionTree);
            }
        }

        // 保存平台订单记录
        SzOrder order = this.saveSystemOrderRecord(otherRule, user, parentId);
        log.info("平台订单保存成功：" + order.getOrderDescription());

        // 获取支付相关 生成支付二维码
        log.info("生成支付二维码");
        String encodeAddress = ShanDeCreateOrder.orderCreate(order);
        log.info("生成二维码路径为：{}", encodeAddress);

        // 将图片转为base64并返回
        try {
            return AjaxResult.success()
                    .put("PaymentQRCode", ImageToBase64Converter.convertToBase64(encodeAddress))
                    .put("orderId", order.getOrderId())
                    .put("orderName", order.getOrderName())
                    .put("orderDescription", order.getOrderDescription())
                    .put("expirationTime", order.getExpirationTime());
        } catch (IOException e) {
            e.printStackTrace();
        }

        return AjaxResult.error();
    }

    /**
     * h5 创建订单
     * @return
     */
    @Override
    public SzOrder createOrderApp(PayVO entity) {
        SzOtherRule otherRule = ruleCache.getOtherRule();
        SzUser user = szUserMapper.selectById(entity.getUserId());
        log.info("管理端，扫码支付    开始保存订单");

        if (StringUtil.isNotEmpty(entity.getParentId())){
            if (szPromotionTreeMapper.selectCount(new LambdaQueryWrapper<SzPromotionTree>().eq(SzPromotionTree::getUserId, entity.getUserId())) ==0 ){
                SzPromotionTree promotionTree = new SzPromotionTree();
                promotionTree.setUserId(Long.parseLong(entity.getUserId()));
                promotionTree.setParentId(Long.parseLong(entity.getParentId()));
                promotionTree.setCreateTime(LocalDateTime.now());
                szPromotionTreeMapper.insert(promotionTree);
            }
        }
        // 保存平台订单记录
        SzOrder order = this.saveSystemOrderRecordApp(otherRule, user, entity);
        log.info("平台订单保存成功：" + order.getOrderDescription());
        return order;
    }

    /**
     * 保存平台订单记录
     * @param otherRule
     * @param user
     * @return
     */
    private SzOrder saveSystemOrderRecordApp(SzOtherRule otherRule, SzUser user,PayVO entity) {
        szOrderMapper.updateOrderState();

        // 判断是否已有未支付订单
        List<SzOrder> orderList = szOrderMapper.selectList(new LambdaQueryWrapper<SzOrder>()
                .eq(SzOrder::getUserId, user.getId())
                .le(SzOrder::getRechargeTime, LocalDateTime.now())
                .ge(SzOrder::getExpirationTime, LocalDateTime.now())
                .eq(SzOrder::getPayState, "1"));
        if (CollectionUtils.isNotEmpty(orderList)){
            szOrderMapper.delete(new LambdaQueryWrapper<SzOrder>()
                    .eq(SzOrder::getUserId, user.getId())
                    .le(SzOrder::getRechargeTime, LocalDateTime.now())
                    .ge(SzOrder::getExpirationTime, LocalDateTime.now())
                    .eq(SzOrder::getPayState, "1"));
        }

        // 创建新订单
        String orderId = com.ruoyi.finance.protal.utils.UUID.getCustomerOrderNo();
        String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        SzOrder order = new SzOrder();
        order.setUserId(user.getId());
        order.setBuyType(user.getSzEnable().equals("0") ? "1" : "2");
        order.setEnergy(otherRule.getEnergy());
        order.setRechargeAmount(otherRule.getPricing());
        order.setRechargeTime(LocalDateTime.now());
        order.setOrderName((user.getSzEnable().equals("0") ? "开通" : "复购" + "数字人直播"));
        order.setOrderDescription(user.getNickname() + (user.getSzEnable().equals("0") ? "开通" : "复购" + "数字人直播") +  nowTime);
        order.setOrderId(orderId);
        order.setBalancePayAmount(entity.getBalancePayAmount());
        order.setActuallyAmount(entity.getActuallyAmount());
        order.setPaymentType("7");
        order.setPayState("1");
        order.setExpirationTime(LocalDateTime.now().plusDays(1));
        order.setParentId(StringUtil.isEmpty(entity.getParentId()) ? null : Long.parseLong(entity.getParentId()));
        szOrderMapper.insert(order);
        return order;
    }

    @Override
    public AjaxResult purchaseOrder(String userId, String paymentType, SzOrder order) {
        List<SzPromotionTree> szPromotionTrees = szPromotionTreeMapper.selectList(new LambdaQueryWrapper<SzPromotionTree>().eq(SzPromotionTree::getUserId, order.getUserId()));
        if (CollectionUtils.isEmpty(szPromotionTrees)){
            return this.separateTopup(userId, paymentType, order) ? AjaxResult.success() : AjaxResult.error();
        }else{
            return this.inviteTopup(userId, szPromotionTrees.get(0).getParentId().toString(), paymentType, order) ? AjaxResult.success() : AjaxResult.error();
        }
    }

    @Override
    public AjaxResult orderPolling(String orderId, HttpServletRequest request) {
        if (StringUtil.isEmpty(orderId)){
            return AjaxResult.error("订单号为空");
        }

        SzOrder order = szOrderMapper.selectOne(new LambdaQueryWrapper<SzOrder>()
                .eq(SzOrder::getOrderId, orderId)
                .le(SzOrder::getRechargeTime, LocalDateTime.now())
                .ge(SzOrder::getExpirationTime, LocalDateTime.now()));

        if (order == null){
            return AjaxResult.success(false);
        }

        if (order.getPayState().equals("5") || order.getPayState().equals("3")){
            return AjaxResult.success(true);
        }

        return AjaxResult.success(false);
    }

    @Override
    public AjaxResult createOrderH5(String userId, String parentId, HttpServletRequest request, HttpServletResponse response) {
        userId = "1";
        SzOtherRule otherRule = ruleCache.getOtherRule();
        SzUser user = szUserMapper.selectById(Long.parseLong(userId));

        // 创建系统订单
        SzOrder order = this.saveSystemOrderRecord(otherRule, user, parentId);
        log.info("平台订单保存成功：" + order.getOrderDescription());

        // 构建请求参数
        Map<String, String> respJson = ShanDeCreateOrderH5.orderCreate(request, response, order);
        return AjaxResult.success(respJson);
    }

    @Override
    @Transactional
    public AjaxResult mutualRechargeBalance(String fromUser, String toUser, BigDecimal money, String paymentPassword) {
        SzUser fromUserInfo = szUserMapper.selectById(Long.parseLong(fromUser));

        if (StringUtil.isEmpty(fromUserInfo.getPaymentPassword())) {
            return AjaxResult.error("充值人未设置支付密码");
        }

        if (!fromUserInfo.getPaymentPassword().equals(paymentPassword)){
            return AjaxResult.error("支付密码错误");
        }

        if (fromUserInfo.getSzEnergy().compareTo(money) < 0){
            return AjaxResult.error("能量值不足");
        }

        if (fromUserInfo.getDeductionAmount().compareTo(BigDecimal.ZERO) != 0){
            return AjaxResult.error(fromUserInfo.getNickname() + "非正常用户，完成还款后可正常对冲");
        }

        if (BigDecimalChain.chain(fromUserInfo.getSzWithdrawalBalance()).sub(fromUserInfo.getFrozenAccount()).get().compareTo(money) < 0){
            return AjaxResult.error(fromUserInfo.getNickname() + "余额不足");
        }

        if (fromUser.equals(toUser)){
            return AjaxResult.error("不能给同一账号对冲");
        }

        if (money.compareTo(BigDecimal.ZERO) == 0){
            return AjaxResult.success();
        }

        // 扣除推荐人余额 能量值
        fromUserInfo.setSzWithdrawalBalance(BigDecimalChain.chain(fromUserInfo.getSzWithdrawalBalance()).sub(money).get());
        fromUserInfo.setSzEnergy(BigDecimalChain.chain(fromUserInfo.getSzEnergy()).sub(money).get());
        szUserMapper.updateById(fromUserInfo);

        // 接收人接受金额
        SzUser toUserInfo = szUserMapper.selectById(toUser);
        toUserInfo.setSzWithdrawalBalance(BigDecimalChain.chain(toUserInfo.getSzWithdrawalBalance()).add(money).get());
        szUserMapper.updateById(toUserInfo);

        // 添加对冲记录
        SzMutualPayRecord mutualPayRecord = new SzMutualPayRecord();
        mutualPayRecord.setFromPerson(fromUserInfo.getId());
        mutualPayRecord.setToPerson(toUserInfo.getId());
        mutualPayRecord.setCreateTime(LocalDateTime.now());
        mutualPayRecord.setMoney(money);
        szMutualPayRecordMapper.insert(mutualPayRecord);

        // 添加提现余额变更记录
        this.saveMutualWithdrawalDetail(fromUserInfo.getId(), money, "3", mutualPayRecord.getId());
        this.saveMutualWithdrawalDetail(toUserInfo.getId(), money, "5", mutualPayRecord.getId());

        // 添加能量值变化记录
        SzEnergyRecord energyRecord = new SzEnergyRecord();
        energyRecord.setUserId(fromUserInfo.getId());
        energyRecord.setCreateTime(LocalDateTime.now());
        energyRecord.setEnergy(money);
        energyRecord.setType("3");
        szEnergyRecordMapper.insert(energyRecord);
        return AjaxResult.success();
    }

    private void saveMutualWithdrawalDetail(Long userId, BigDecimal money, String flowType, Long mutualPayId){
        SzWithdrawalDetail withdrawalDetail = new SzWithdrawalDetail();
        withdrawalDetail.setUserId(userId);
        withdrawalDetail.setMoney(money);
        withdrawalDetail.setFlowType(flowType);
        withdrawalDetail.setMutualPay(mutualPayId);
        withdrawalDetail.setCreateTime(LocalDateTime.now());
        szWithdrawalDetailMapper.insert(withdrawalDetail);
    }



    private SzOrder saveSystemOrderRecord(SzOtherRule otherRule, SzUser user, String parentId) {
        szOrderMapper.updateOrderState();

        // 判断是否已有未支付订单
        List<SzOrder> orderList = szOrderMapper.selectList(new LambdaQueryWrapper<SzOrder>()
                .eq(SzOrder::getUserId, user.getId())
                .le(SzOrder::getRechargeTime, LocalDateTime.now())
                .ge(SzOrder::getExpirationTime, LocalDateTime.now())
                .eq(SzOrder::getPayState, "1"));
        if (CollectionUtils.isNotEmpty(orderList)){
            szOrderMapper.delete(new LambdaQueryWrapper<SzOrder>()
                    .eq(SzOrder::getUserId, user.getId())
                    .le(SzOrder::getRechargeTime, LocalDateTime.now())
                    .ge(SzOrder::getExpirationTime, LocalDateTime.now())
                    .eq(SzOrder::getPayState, "1"));
        }

        // 创建新订单
        String orderId = com.ruoyi.finance.protal.utils.UUID.getCustomerOrderNo();
        String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        SzOrder order = new SzOrder();
        order.setUserId(user.getId());
        order.setBuyType(user.getSzEnable().equals("0") ? "1" : "2");
        order.setEnergy(otherRule.getEnergy());
        order.setRechargeAmount(otherRule.getPricing());
        order.setRechargeTime(LocalDateTime.now());
        order.setOrderName((user.getSzEnable().equals("0") ? "开通" : "复购" + "数字人直播"));
        order.setOrderDescription(user.getNickname() + (user.getSzEnable().equals("0") ? "开通" : "复购" + "数字人直播") +  nowTime);
        order.setOrderId(orderId);
        order.setPaymentType("7");
        order.setPayState("1");
        order.setExpirationTime(LocalDateTime.now().plusDays(1));
        order.setParentId(StringUtil.isEmpty(parentId) ? null : Long.parseLong(parentId));
        order.setActuallyAmount(otherRule.getPricing());
        order.setBalancePayAmount(BigDecimal.ZERO);
        szOrderMapper.insert(order);
        return order;
    }

    private List<SzPromotionTree> buildTree(List<SzPromotionTree> userList, Long userId) {
        return userList.stream()
                .filter(item -> item.getParentId().equals(userId))
                .map(item -> {
                    SzPromotionTree node = item;
                    List<SzPromotionTree> subTree = buildTree(userList, item.getUserId());
                    node.setChildren(subTree);
                    return node;
                }).collect(Collectors.toList());
    }

    private BigDecimal calculateTotalAmount(SzPromotionTree user) {
        BigDecimal totalAmount = user.getMoney();
        List<SzPromotionTree> children = user.getChildren();
        if (children != null && !children.isEmpty()) {
            totalAmount = totalAmount.add(
                    children.stream()
                            .map(this::calculateTotalAmount)
                            .reduce(BigDecimal.ZERO, BigDecimal::add)
            );
        }
        user.setMoneySum(totalAmount);
        return totalAmount;
    }

    /**
     * Deduct the balance of the top-up
     * 扣除充值人余额
     */
    private void deductBalanceOfTopupFree(CounterChargeVO vo) {
        log.info("对冲：{} 》》》 {}", vo.getFromUser(), vo.getToUser());
        SzMutualPayRecord mutualPayRecord = new SzMutualPayRecord();
        mutualPayRecord.setCreateTime(LocalDateTime.now());
        mutualPayRecord.setFromPerson(Long.parseLong( vo.getFromUser()));
        mutualPayRecord.setToPerson(Long.parseLong(vo.getToUser()));
        szMutualPayRecordMapper.insert(mutualPayRecord);
        log.info("对冲记录表插入成功");

        SzUser user = szUserMapper.selectById( vo.getFromUser());
        user.setSzWithdrawalBalance(BigDecimalChain.chain(user.getSzWithdrawalBalance()).sub(vo.getPricing()).get());
        user.setSzEnergy(BigDecimalChain.chain(user.getSzEnergy()).sub(vo.getPricing()).get());
        szUserMapper.updateById(user);
        log.info("对冲金额扣除成功：{}元", vo.getPricing());
        log.info("{} 账户可提现余额剩余{}；能量值剩余{}", user.getNickname(), user.getSzWithdrawalBalance(), user.getSzEnergy());

        SzWithdrawalDetail withdrawalDetail = new SzWithdrawalDetail();
        withdrawalDetail.setUserId(Long.parseLong( vo.getFromUser()));
        withdrawalDetail.setMoney(vo.getPricing());
        withdrawalDetail.setFlowType("3");
        withdrawalDetail.setMutualPay(mutualPayRecord.getId());
        withdrawalDetail.setCreateTime(LocalDateTime.now());
        szWithdrawalDetailMapper.insert(withdrawalDetail);
        log.info("提现钱包余额明细记录插入成功");

        SzEnergyRecord energyRecord = new SzEnergyRecord();
        energyRecord.setUserId(Long.parseLong( vo.getFromUser()));
        energyRecord.setCreateTime(LocalDateTime.now());
        energyRecord.setEnergy(vo.getPricing());
        energyRecord.setType("3");
        szEnergyRecordMapper.insert(energyRecord);
        log.info("能量值变化记录插入成功");
    }


    /**
     * Deduct the balance of the top-up
     * 扣除充值人余额
     */
    private void deductBalanceOfTopup(String fromUser, String toUser) {
        SzOtherRule otherRule = ruleCache.getOtherRule();
        log.info("对冲：{} 》》》 {}", fromUser, toUser);

        SzMutualPayRecord mutualPayRecord = new SzMutualPayRecord();
        mutualPayRecord.setCreateTime(LocalDateTime.now());
        mutualPayRecord.setFromPerson(Long.parseLong(fromUser));
        mutualPayRecord.setToPerson(Long.parseLong(toUser));
        szMutualPayRecordMapper.insert(mutualPayRecord);
        log.info("对冲记录表插入成功");

        SzUser user = szUserMapper.selectById(fromUser);
        user.setSzWithdrawalBalance(BigDecimalChain.chain(user.getSzWithdrawalBalance()).sub(otherRule.getPricing()).get());
        user.setSzEnergy(BigDecimalChain.chain(user.getSzEnergy()).sub(otherRule.getPricing()).get());
        szUserMapper.updateById(user);
        log.info("对冲金额扣除成功：{}元", otherRule.getPricing());
        log.info("{} 账户可提现余额剩余{}；能量值剩余{}", user.getNickname(), user.getSzWithdrawalBalance(), user.getSzEnergy());

        SzWithdrawalDetail withdrawalDetail = new SzWithdrawalDetail();
        withdrawalDetail.setUserId(Long.parseLong(fromUser));
        withdrawalDetail.setMoney(otherRule.getPricing());
        withdrawalDetail.setFlowType("3");
        withdrawalDetail.setMutualPay(mutualPayRecord.getId());
        withdrawalDetail.setCreateTime(LocalDateTime.now());
        szWithdrawalDetailMapper.insert(withdrawalDetail);
        log.info("提现钱包余额明细记录插入成功");

        SzEnergyRecord energyRecord = new SzEnergyRecord();
        energyRecord.setUserId(Long.parseLong(fromUser));
        energyRecord.setCreateTime(LocalDateTime.now());
        energyRecord.setEnergy(otherRule.getPricing());
        energyRecord.setType("3");
        szEnergyRecordMapper.insert(energyRecord);
        log.info("能量值变化记录插入成功");
    }


    /**
     * 单独充值
     */
    public boolean separateTopup(String userId, String paymentType, SzOrder order){
        log.info("用户{}充值数字人直播； 没有推荐人", userId);
        SzUser szUser = szUserMapper.selectById(userId);
        if ("0".equals(szUser.getSzEnable())){
            log.info("首次开通");
            return this.firstPurchase(szUser, paymentType, order);
        }else{
            log.info("复购");
            return this.repeatPurchase(szUser, paymentType, order);
        }
    }

    /**
     * 单独充值 抵扣支付
     */
    public boolean deductionSeparateTopup(String userId, String paymentType, SzOrder order, BigDecimal amount, BigDecimal deductionAmount){
        log.info("用户{}充值数字人直播（抵扣支付 实际支付：{}元，抵扣：{}元）； 没有推荐人", userId, amount, deductionAmount);
        SzUser szUser = szUserMapper.selectById(userId);
        if ("0".equals(szUser.getSzEnable())){
            log.info("首次开通");
            return this.deductionFirstPurchase(szUser, paymentType, order, amount, deductionAmount);
        }else{
            log.info("复购");
            return this.deductionRepeatPurchase(szUser, paymentType, order, amount, deductionAmount);
        }
    }

    /**
     * 单独充值
     */
    public boolean separateTopupFree(String userId, String paymentType, SzOrder order,CounterChargeVO vo){
        log.info("用户{}充值数字人直播； 没有推荐人", userId);
        SzUser szUser = szUserMapper.selectById(userId);
        if ("0".equals(szUser.getSzEnable())){
            log.info("首次开通");
            return this.firstPurchaseFree(szUser, paymentType, order,vo);
        }else{
            log.info("复购");
            return this.repeatPurchaseFree(szUser, paymentType, order,vo);
        }
    }


    /**
     * 单独充值 -- 首次购买
     */
    private boolean firstPurchase(SzUser user, String paymentType, SzOrder order){
        updateSeparateBuyInfo(user, "1", paymentType, "5", order);
        return true;
    }

    /**
     * 单独充值 -- 复购
     */
    private boolean repeatPurchase(SzUser user, String paymentType, SzOrder order){
        updateSeparateBuyInfo(user, "2",paymentType, "5", order);
        return true;
    }

    /**
     * 单独充值 -- 首次购买 抵扣支付
     */
    private boolean deductionFirstPurchase(SzUser user, String paymentType, SzOrder order, BigDecimal amount, BigDecimal deductionAmount){
        deductionUpdateSeparateBuyInfo(user, "4", paymentType, "5", order, amount, deductionAmount);
        return true;
    }

    /**
     * 单独充值 -- 复购  抵扣支付
     */
    private boolean deductionRepeatPurchase(SzUser user, String paymentType, SzOrder order, BigDecimal amount, BigDecimal deductionAmount){
        deductionUpdateSeparateBuyInfo(user, "2",paymentType, "5", order, amount, deductionAmount);
        return true;
    }

    /**
     * 单独充值 -- 首次购买
     */
    private boolean firstPurchaseFree(SzUser user, String paymentType, SzOrder order,CounterChargeVO vo){
        updateSeparateBuyInfoFree(user, "1", paymentType, "5", order, vo);
        return true;
    }

    /**
     * 单独充值 -- 复购
     */
    private boolean repeatPurchaseFree(SzUser user, String paymentType, SzOrder order,CounterChargeVO vo){
        updateSeparateBuyInfoFree(user, "2",paymentType, "5", order, vo);
        return true;
    }


    /**
     * 购买必要信息修改 现金支付
     * @param buyType: 购买类型 DMC011
     * @param paymentType: 付款方式 DMC003
     * @param payState：支付状态 DMC014
     * @return
     */
    private Long updateSeparateBuyInfoFree(SzUser user, String buyType, String paymentType, String payState, SzOrder order, CounterChargeVO vo) {
        List<SzVipRule> vipRules = ruleCache.getVipRules();
        log.info("加载基础信息{}", vo);
        log.info("加载VIP规则信息{}", vipRules);

        user.setSzEnableTime("2".equals(buyType) ? user.getSzEnableTime() : LocalDateTime.now());
        user.setSzAgency("2".equals(buyType) ? user.getSzAgency() : vipRules.get(0).getId());
        user.setSzEnable("2".equals(buyType) ? user.getSzEnable() : "1");
        user.setSzEnergy(BigDecimalChain
                .chain(user.getSzEnergy())
                .add(vo.getEnergy())
                .get());
        user.setVoucher(BigDecimalChain
                .chain(user.getVoucher())
                .add(vo.getPricing())
                .get());
        szUserMapper.updateById(user);
        log.info("修改用户表信息成功");

        if ("1".equals(buyType) || "4".equals(buyType)){
            Long day = Duration.between(user.getRegisterTime(), LocalDateTime.now()).toDays();
            SzVipUpgradeRecord vipUpgradeRecord = new SzVipUpgradeRecord();
            vipUpgradeRecord.setCreateTime(LocalDateTime.now());
            vipUpgradeRecord.setUserId(user.getId());
            vipUpgradeRecord.setElapsedDay(day.intValue());
            vipUpgradeRecord.setVipId(vipRules.get(0).getId());
            szVipUpgradeRecordMapper.insert(vipUpgradeRecord);
        }

        if (order == null){
            order = new SzOrder();
            order.setUserId(user.getId());
            order.setBuyType(buyType);
            order.setEnergy(order.getEnergy());
            order.setRechargeAmount(vo.getPricing());
            order.setRechargeTime(LocalDateTime.now());
            order.setPaymentType(paymentType); // 现金
            order.setPaymentTime(LocalDateTime.now());
            order.setOrderName(user.getNickname() + "开通数字人直播订单");
            order.setOrderId(generateOrderId());
            order.setPayId(generateOrderId());
            order.setPayState(payState);
            order.setRemark("现金交易");
            szOrderMapper.insert(order);
            log.info("插入购买记录表成功");
        }

        SzEnergyRecord energyRecord = new SzEnergyRecord();
        energyRecord.setUserId(user.getId());
        energyRecord.setEnergy(vo.getEnergy());
        energyRecord.setCreateTime(LocalDateTime.now());
        energyRecord.setType("1"); // 充值获得
        szEnergyRecordMapper.insert(energyRecord);
        log.info("插入能量值变化记录成功");
        return order.getId();
    }

    /**
     * 购买必要信息修改 现金支付
     * @param buyType: 购买类型 DMC011
     * @param paymentType: 付款方式 DMC003
     * @param payState：支付状态 DMC014
     * @return
     */
    private Long updateSeparateBuyInfo(SzUser user, String buyType, String paymentType, String payState, SzOrder order){
        SzOtherRule otherRule = ruleCache.getOtherRule();
        List<SzVipRule> vipRules = ruleCache.getVipRules();
        log.info("加载基础信息{}", otherRule);
        log.info("加载VIP规则信息{}", vipRules);

        user.setSzEnableTime("2".equals(buyType) ? user.getSzEnableTime() : LocalDateTime.now());
        user.setSzAgency("2".equals(buyType) ? user.getSzAgency() : vipRules.get(0).getId());
        user.setSzEnable(judgmentBugType(user, buyType));
        user.setSzEnergy(BigDecimalChain
                .chain(user.getSzEnergy())
                .add(otherRule.getEnergy())
                .get());
        user.setVoucher(BigDecimalChain
                .chain(user.getVoucher())
                .add(otherRule.getPricing())
                .get());
        if (Objects.nonNull(order) && Objects.nonNull(order.getBalancePayAmount())){
            user.setSzWalletBalance(user.getSzWalletBalance().subtract(order.getBalancePayAmount()));
        }
        szUserMapper.updateById(user);
        log.info("修改用户表信息成功");

        if ("1".equals(buyType) || "4".equals(buyType)){
            Long day = Duration.between(user.getRegisterTime(), LocalDateTime.now()).toDays();
            SzVipUpgradeRecord vipUpgradeRecord = new SzVipUpgradeRecord();
            vipUpgradeRecord.setCreateTime(LocalDateTime.now());
            vipUpgradeRecord.setUserId(user.getId());
            vipUpgradeRecord.setElapsedDay(day.intValue());
            vipUpgradeRecord.setVipId(vipRules.get(0).getId());
            szVipUpgradeRecordMapper.insert(vipUpgradeRecord);
        }

        if (order == null){
            order = new SzOrder();
            order.setUserId(user.getId());
            order.setBuyType(buyType);
            order.setEnergy(order.getEnergy());
            order.setRechargeAmount(otherRule.getPricing());
            order.setRechargeTime(LocalDateTime.now());
            order.setPaymentType(paymentType); // 现金
            order.setPaymentTime(LocalDateTime.now());
            order.setOrderName(user.getNickname() + "开通数字人直播订单");
            order.setOrderId(generateOrderId());
            order.setPayId(generateOrderId());
            order.setPayState(payState);
            order.setRemark("现金交易");
            order.setActuallyAmount(otherRule.getPricing());
            order.setBalancePayAmount(BigDecimal.ZERO);
            szOrderMapper.insert(order);
            log.info("插入购买记录表成功");
        }

        SzEnergyRecord energyRecord = new SzEnergyRecord();
        energyRecord.setUserId(user.getId());
        energyRecord.setEnergy(otherRule.getEnergy());
        energyRecord.setCreateTime(LocalDateTime.now());
        energyRecord.setType("1"); // 充值获得
        szEnergyRecordMapper.insert(energyRecord);
        log.info("插入能量值变化记录成功");
        return order.getId();
    }

    private String judgmentBugType(SzUser user, String buyType){
        if ("2".equals(buyType)){
            if (user.getDeductionAmount().compareTo(BigDecimal.ZERO) == 0){
                return "1";
            }else{
                return "2";
            }
        }else{
            return "1";
        }
    }


    /**
     * 购买必要信息修改 现金支付            抵扣支付
     * @param buyType: 购买类型 DMC011
     * @param paymentType: 付款方式 DMC003
     * @param payState：支付状态 DMC014
     * @return
     */
    private Long deductionUpdateSeparateBuyInfo(SzUser user, String buyType, String paymentType, String payState, SzOrder order, BigDecimal amount, BigDecimal deductionAmount){
        SzOtherRule otherRule = ruleCache.getOtherRule();
        List<SzVipRule> vipRules = ruleCache.getVipRules();
        log.info("加载基础信息{}", otherRule);
        log.info("加载VIP规则信息{}", vipRules);

        SzDeductionAmountRecord deductionAmountRecord = new SzDeductionAmountRecord();
        deductionAmountRecord.setUserId(user.getId());
        deductionAmountRecord.setAmount(deductionAmount);
        deductionAmountRecord.setType("2".equals(buyType) ? "2" : "1");
        deductionAmountRecord.setCreateTime(LocalDateTime.now());
        deductionAmountRecord.setBeforAmount(user.getDeductionAmount());

        user.setSzEnableTime("2".equals(buyType) ? user.getSzEnableTime() : LocalDateTime.now());
        user.setSzAgency("2".equals(buyType) ? user.getSzAgency() : vipRules.get(0).getId());
        user.setSzEnable("2");  // 抵扣开通
        user.setSzEnergy(BigDecimalChain
                .chain(user.getSzEnergy())
                .add(otherRule.getEnergy())
                .get());
        user.setVoucher(BigDecimalChain
                .chain(user.getVoucher())
                .add(otherRule.getPricing())
                .get());
        user.setDeductionAmount(BigDecimalChain
                .chain(user.getDeductionAmount())
                .add(deductionAmount)
                .get());
        if (Objects.nonNull(order) && Objects.nonNull(order.getBalancePayAmount())){
            user.setSzWalletBalance(user.getSzWalletBalance().subtract(order.getBalancePayAmount()));
        }
        szUserMapper.updateById(user);
        log.info("修改用户表信息成功");

        if ("1".equals(buyType) || "4".equals(buyType)){
            Long day = Duration.between(user.getRegisterTime(), LocalDateTime.now()).toDays();
            SzVipUpgradeRecord vipUpgradeRecord = new SzVipUpgradeRecord();
            vipUpgradeRecord.setCreateTime(LocalDateTime.now());
            vipUpgradeRecord.setUserId(user.getId());
            vipUpgradeRecord.setElapsedDay(day.intValue());
            vipUpgradeRecord.setVipId(vipRules.get(0).getId());
            szVipUpgradeRecordMapper.insert(vipUpgradeRecord);
        }

        if (order == null){
            order = new SzOrder();
            order.setUserId(user.getId());
            order.setBuyType("2".equals(buyType) ? "5" : "4"); // 抵扣复购 、抵扣开通
            order.setEnergy(order.getEnergy());
            order.setRechargeAmount(otherRule.getPricing());
            order.setRechargeTime(LocalDateTime.now());
            order.setPaymentType(paymentType); // 现金
            order.setPaymentTime(LocalDateTime.now());
            order.setOrderName(user.getNickname() + "抵扣开通数字人直播订单");
            order.setOrderId(generateOrderId());
            order.setPayId(generateOrderId());
            order.setPayState(payState);
            order.setRemark("现金交易");
            order.setActuallyAmount(amount);
            order.setBalancePayAmount(deductionAmount);
            order.setActuallyAmount(amount);
            order.setBalancePayAmount(deductionAmount);
            szOrderMapper.insert(order);
            log.info("插入购买记录表成功");
        }

        SzEnergyRecord energyRecord = new SzEnergyRecord();
        energyRecord.setUserId(user.getId());
        energyRecord.setEnergy(otherRule.getEnergy());
        energyRecord.setCreateTime(LocalDateTime.now());
        energyRecord.setType("1"); // 充值获得
        szEnergyRecordMapper.insert(energyRecord);
        log.info("插入能量值变化记录成功");

        deductionAmountRecord.setOrderId(order.getId());
        deductionAmountRecord.setAfterAmount(user.getDeductionAmount());
        szDeductionAmountRecordMapper.insert(deductionAmountRecord);
        return order.getId();
    }



    /**
     * 生成随机订单号
     * @return
     */
    private static String generateOrderId() {
        long timestamp = System.currentTimeMillis();
        String random = UUID.randomUUID().toString().replaceAll("-", "");
        log.info("生成交易订单号：{}", timestamp + random);
        return timestamp + random;
    }


    /**
     * 有邀请人充值
     */
    public boolean inviteTopup(String userId, String parentId, String paymentType, SzOrder order){
        SzUser user = szUserMapper.selectById(userId);
        SzUser parentUser = szUserMapper.selectById(parentId);
        log.info("用户{}充值数字人直播； 推荐人{}", user.getNickname(), parentUser.getNickname());

        if ("0".equals(user.getSzEnable())){
            log.info("首次开通");
            return this.firstInvitePurchase(user, parentUser, paymentType, order);
        }else{
            log.info("复购");
            return this.repeatInvitePurchase(user, parentUser, paymentType, order);
        }
    }


    /**
     * 有邀请人充值   抵扣支付
     */
    public boolean deductionInviteTopup(String userId, String parentId, String paymentType, SzOrder order, BigDecimal amount, BigDecimal deductionAmount){
        SzUser user = szUserMapper.selectById(userId);
        SzUser parentUser = szUserMapper.selectById(parentId);
        log.info("用户{}充值数字人直播（抵扣支付 实际支付：{}元，抵扣：{}元）； 推荐人{}", user.getNickname(), amount, deductionAmount, parentUser.getNickname());

        if ("0".equals(user.getSzEnable())){
            log.info("首次开通");
            return this.deductionFirstInvitePurchase(user, parentUser, paymentType, order, amount, deductionAmount);
        }else{
            log.info("复购");
            return this.deductionRepeatInvitePurchase(user, parentUser, paymentType, order, amount, deductionAmount);
        }
    }

    /**
     * 有邀请人充值
     */
    public boolean inviteTopupFree(String userId, String parentId, String paymentType, SzOrder order,CounterChargeVO vo){
        SzUser user = szUserMapper.selectById(userId);
        SzUser parentUser = szUserMapper.selectById(parentId);
        log.info("用户{}充值数字人直播； 推荐人{}", user.getNickname(), parentUser.getNickname());

        if ("0".equals(user.getSzEnable())){
            log.info("首次开通");
            return this.firstInvitePurchaseFree(user, parentUser, paymentType, order,vo);
        }else{
            log.info("复购");
            return this.repeatInvitePurchaseFree(user, parentUser, paymentType, order,vo);
        }
    }

    /**
     * 有邀请人 -- 首次开通
     */
    private boolean firstInvitePurchase(SzUser user, SzUser parentUser, String paymentType, SzOrder order) {

        // 更新购买记录
        Long orderId = this.updateSeparateBuyInfo(user, "1", paymentType, "5", order);

        // 更新推荐关系
        this.insertPromotionRecord(user.getId(), parentUser.getId());

        // 获取用户所有上级用户
        List<Map<String, Long>> upperLevelUser = this.getUpperLevelUser(user.getId());

        // 发放奖励
        this.issueReward(upperLevelUser, user, orderId);

        // 更新所有上级用户的代理等级
        this.updateVIPLevel(upperLevelUser);

        return true;
    }


    /**
     * 有邀请人充值 -- 复购
     */
    private boolean repeatInvitePurchaseFree(SzUser user, SzUser parentUser, String paymentType, SzOrder order,CounterChargeVO vo){
        List<Boolean> result = new ArrayList<>();

        // 更新购买记录
        Long orderId = this.updateSeparateBuyInfoFree(user, "2", paymentType, "5", order,vo);

        // 更新推荐关系
        result.add(this.insertPromotionRecord(user.getId(), parentUser.getId()));

        // 更新推荐人的余额
        result.add(this.updateReferrerBalance(user, parentUser, "5", orderId));

        // 获取用户所有上级用户
        List<Map<String, Long>> upperLevelUser = this.getUpperLevelUser(user.getId());

        // 更新所有上级用户的代理等级
        this.updateVIPLevel(upperLevelUser);

        return result.stream().allMatch(res -> res);
    }


    /**
     * 有邀请人 -- 首次开通  抵扣开通
     */
    private boolean deductionFirstInvitePurchase(SzUser user, SzUser parentUser, String paymentType, SzOrder order, BigDecimal amount, BigDecimal deductionAmount) {

        // 更新购买记录
        Long orderId = this.deductionUpdateSeparateBuyInfo(user, "4", paymentType, "5", order, amount, deductionAmount);

        // 更新推荐关系
        this.insertPromotionRecord(user.getId(), parentUser.getId());

        // 获取用户所有上级用户
        List<Map<String, Long>> upperLevelUser = this.getUpperLevelUser(user.getId());

        // 发放奖励
        this.issueReward(upperLevelUser, user, orderId);

        // 更新所有上级用户的代理等级
        this.updateVIPLevel(upperLevelUser);

        return true;
    }


    /**
     * 有邀请人充值 -- 复购  抵扣开通
     */
    private boolean deductionRepeatInvitePurchase(SzUser user, SzUser parentUser, String paymentType, SzOrder order, BigDecimal amount, BigDecimal deductionAmount){
        List<Boolean> result = new ArrayList<>();

        // 更新购买记录
        Long orderId = this.deductionUpdateSeparateBuyInfo(user, "2", paymentType, "5", order, amount, deductionAmount);

        // 更新推荐关系
        result.add(this.insertPromotionRecord(user.getId(), parentUser.getId()));

        // 更新推荐人的余额
        result.add(this.updateReferrerBalance(user, parentUser, "5", orderId));

        // 获取用户所有上级用户
        List<Map<String, Long>> upperLevelUser = this.getUpperLevelUser(user.getId());

        // 更新所有上级用户的代理等级
        this.updateVIPLevel(upperLevelUser);

        return result.stream().allMatch(res -> res);
    }




    /**
     * 有邀请人 -- 首次开通
     */
    private boolean firstInvitePurchaseFree(SzUser user, SzUser parentUser, String paymentType, SzOrder order,CounterChargeVO vo) {

        // 更新购买记录
        Long orderId = this.updateSeparateBuyInfoFree(user, "1", paymentType, "5", order,vo);

        // 更新推荐关系
        this.insertPromotionRecord(user.getId(), parentUser.getId());

        // 获取用户所有上级用户
        List<Map<String, Long>> upperLevelUser = this.getUpperLevelUser(user.getId());

        // 发放奖励
        this.issueReward(upperLevelUser, user, orderId);

        // 更新所有上级用户的代理等级
        this.updateVIPLevel(upperLevelUser);

        return true;
    }


    /**
     * 有邀请人充值 -- 复购
     */
    private boolean repeatInvitePurchase(SzUser user, SzUser parentUser, String paymentType, SzOrder order){
        List<Boolean> result = new ArrayList<>();

        // 更新购买记录
        Long orderId = this.updateSeparateBuyInfo(user, "2", paymentType, "5", order);

        // 更新推荐关系
        result.add(this.insertPromotionRecord(user.getId(), parentUser.getId()));

        // 更新推荐人的余额
        result.add(this.updateReferrerBalance(user, parentUser, "5", orderId));

        // 获取用户所有上级用户
        List<Map<String, Long>> upperLevelUser = this.getUpperLevelUser(user.getId());

        // 更新所有上级用户的代理等级
        this.updateVIPLevel(upperLevelUser);

        return result.stream().allMatch(res -> res);
    }

    /**
     * 保存推广关系
     * @return
     */
    private boolean insertPromotionRecord(Long userId, Long parentId){
        log.info("插入用户推广关系");
        List<SzPromotionTree> szPromotionTrees = szPromotionTreeMapper.selectList(new LambdaQueryWrapper<SzPromotionTree>()
                .eq(SzPromotionTree::getUserId, userId));
        if(CollectionUtils.isEmpty(szPromotionTrees)){
            SzUser user = szUserMapper.selectById(userId);
            user.setInvitationParent(szUserMapper.selectOne(new LambdaQueryWrapper<SzUser>().eq(SzUser::getId, parentId).select(SzUser::getInvitationCode)).getInvitationCode());
            szUserMapper.updateById(user);

            SzPromotionTree promotionTree = new SzPromotionTree();
            promotionTree.setCreateTime(LocalDateTime.now());
            promotionTree.setUserId(userId);
            promotionTree.setParentId(parentId);
            return szPromotionTreeMapper.insert(promotionTree) == 1 ? true : false;
        }else{
            return  szPromotionTrees.get(0).getParentId().equals(parentId) ? true : false;
        }
    }


    /**
     * 更新推荐人余额
     * @param user
     * @param parentUser
     * @param flowType  余额流动类型 DMC008
     * @param orderId   数字直播购买记录id
     */
    private boolean updateReferrerBalance(SzUser user, SzUser parentUser, String flowType, Long orderId){
        log.info("{}复购，更新推荐人{}账户余额", user.getNickname(), parentUser.getNickname());
        if (parentUser.getSzAgency() == null || parentUser.getSzAgency().equals(0L)){
            log.info("发放复购奖励时，推荐人{}未开通数字人直播，暂不发放", parentUser.getNickname());
            return true;
        }

        if (StringUtil.isEmpty(parentUser.getIsFrozen()) || "1".equals(parentUser.getIsFrozen())){
            log.info("发放复购奖励时，推荐人{} 数字直播已被冻结，暂不发放", parentUser.getNickname());
            return true;
        }

        if (StringUtil.isEmpty(parentUser.getIsSignOut()) || "1".equals(parentUser.getIsSignOut())){
            log.info("发放复购奖励时，推荐人{} 平台账号已被注销，暂不发放", parentUser.getNickname());
            return true;
        }

        if ("1".equals(parentUser.getDeleteFlag())){
            log.info("发放复购奖励时，推荐人{} 平台账号已被管理员删除，暂不发放", parentUser.getNickname());
            return true;
        }

        SzOtherRule otherRule = ruleCache.getOtherRule();
        Long recordId = null;
        BigDecimalChain award = null;
        BigDecimal deductionAmount = user.getDeductionAmount();

        if (!"1".equals(flowType)){
            //计算复购奖励获得之后的余额
            award  = BigDecimalChain
                    .chain(otherRule.getPricing())
                    .mul(otherRule.getRepeatBuyRatio())
                    .mul(new BigDecimal("1.00").subtract(otherRule.getDonateRatio()));
            log.info("计算{}购买产品花费{}  复购奖励比例{}  公益基金比例{}  计算可获得{}",
                    user.getNickname(), otherRule.getPricing(), otherRule.getRepeatBuyRatio(), otherRule.getDonateRatio(), award.get());

            SzUser updateParentUser = szUserMapper.selectById(parentUser.getId());

            updateParentUser.setSzWalletBalance(BigDecimalChain
                    .chain(parentUser.getSzWalletBalance())
                    .add(award.get()).get());
            updateParentUser.setSzRepeatbuyReword(BigDecimalChain
                    .chain(updateParentUser.getSzRepeatbuyReword())
                    .add(award.get()).get());
            if (deductionAmount.compareTo(BigDecimal.ZERO) != 0){
                updateParentUser.setPendingActivationBalance(BigDecimalChain
                        .chain(updateParentUser.getPendingActivationBalance())
                        .add(award.get()).get());
            }
            szUserMapper.updateById(updateParentUser);

            log.info("插入所获奖励记录表");
            SzAwardRecord awardRecord = new SzAwardRecord();
            awardRecord.setBeneficiary(parentUser.getId());
            awardRecord.setBuyPerson(user.getId());
            awardRecord.setOrderId(orderId);
            awardRecord.setGetTime(LocalDateTime.now());
            awardRecord.setGetMoney(BigDecimalChain
                    .chain(otherRule.getPricing())
                    .mul(otherRule.getRepeatBuyRatio()).get());
            awardRecord.setDonateRatio(otherRule.getDonateRatio());
            awardRecord.setActualMoney(award.get());
            awardRecord.setType(convertFlowType(flowType, deductionAmount));
            awardRecord.setRepeatBuyRatio(otherRule.getRepeatBuyRatio());
            szAwardRecordMapper.insert(awardRecord);
            recordId = awardRecord.getId();
        }

        log.info("更新推荐人余额记录表");
        SzWalletDetail walletDetail = new SzWalletDetail();
        walletDetail.setUserId(parentUser.getId());
        walletDetail.setMoney(award.get());
        walletDetail.setFlowType(convertFlowType(flowType, deductionAmount));
        walletDetail.setOrderId(orderId);
        walletDetail.setAwardId(!"1".equals(flowType) ? recordId : null);
        walletDetail.setCreateTime(LocalDateTime.now());
        walletDetail.setPlayTour("1".equals(flowType) ? recordId : null);
        szWalletDetailMapper.insert(walletDetail);

        return true;
    }

    private String convertFlowType(String flowType, BigDecimal deductionAmount){
        if ("1".equals(flowType)){
            return flowType;
        }

        if (deductionAmount.compareTo(BigDecimal.ZERO) == 0){
            return flowType;
        }

        return flowType + "0";
    }

    /**
     * 获取此用户的所有上级用户
     */
    private List<Map<String, Long>> getUpperLevelUser(Long userId){
        Map<Long, Long> userAgency = szUserMapper.selectList(new LambdaQueryWrapper<SzUser>())
                .stream().collect(Collectors.toMap(SzUser::getId, user -> user.getSzAgency() == null ? 0 : user.getSzAgency()));

        return szUserMapper.getUpperLevelUser(userId).stream().peek(userMap -> {
            if (!userMap.containsKey("vip") && userMap.get("vip") == null) {
                Long parentId = userMap.get("parent_id");
                userMap.put("vip", userAgency.get(parentId));
            }
        }).collect(Collectors.toList());
    }


    /**
     * 更新VIP等级
     */
    private void updateVIPLevel(List<Map<String, Long>> upperLevelUser) {
        for (Map<String, Long> map : upperLevelUser) {
            Long parentId = map.get("parent_id");
            Long vip = map.get("vip");

            if (vip == null || vip.equals(0L)){
                log.info("用户{} 未开通vip，暂不考虑升级", parentId);
                continue;
            }

            List<Map<String, Object>> branchLink = szUserMapper.getBranchLink(parentId);
            List<SzVipRule> vipRules = this.filterVipRules(vip);
            log.info("尝试更新用户{}的代理VIP等级", parentId);

            // 一星升级二星特殊处理
            if (this.checkUpgradeCondition(parentId, vip, branchLink, vipRules) && (vip == 1L && checkUpgradeTwoStars(branchLink, vipRules))) {
                log.info("用户 {} 达到 {} 升级条件", parentId, vipRules.get(1).getVipName());
                this.upgradeVip(parentId, vipRules.get(1).getId());
            } else {
                log.info("用户 {} 未达到 {} 升级条件", parentId, vipRules.get(1).getVipName());
            }

        }
    }

    // 一星升级二星，判断总额是否达到要求
    public boolean checkUpgradeTwoStars(List<Map<String, Object>> branchLink,  List<SzVipRule> vipRules){
        SzVipRule szVipRule = vipRules.get(1);
        BigDecimal totalAmountSum = branchLink.stream()
                .map(map -> (BigDecimal) map.get("total_amount"))
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        return totalAmountSum.compareTo(szVipRule.getTwoStarsMoney()) >= 0;
    }

    /**
     * 判断此用户能否升级
     * @param parentId  用户id
     * @param vip       用户所处VIP id
     * @param branchLink    用户下所有链路的消费情况
     * @param vipRules      用户下一等级VIP 升级规则
     */
    private boolean checkUpgradeCondition(Long parentId, Long vip, List<Map<String, Object>> branchLink, List<SzVipRule> vipRules){
        if (vipRules.size() == 1){
            log.warn("用户{}已经达到代理的最高等级vip_id = {}，无需升级", parentId, vip);
            return false;
        }

        BigDecimal totalAmount = this.calculateTotalAmount(branchLink);
        return this.isUpgradeAchieved(vipRules, totalAmount, parentId);
    }


    /**
     * 获取当前VIP等级 和下一等级信息
     */
    private List<SzVipRule> filterVipRules(Long id) {
        return ruleCache.getVipRules().stream()
                .filter(rule -> rule.getId().equals(id) || rule.getSonId().equals(id))
                .sorted((rule1, rule2) -> Integer.compare(rule1.getSort(), rule2.getSort()))
                .collect(Collectors.toList());
    }


    /**
     * 去掉最大分支，计算剩余分支的总消费额
     */
    private BigDecimal calculateTotalAmount(List<Map<String, Object>> branchLink) {
        // 拿到最高的消费额
        Optional<BigDecimal> maxAmount = branchLink.stream()
                .map(branch -> (BigDecimal) branch.get("total_amount"))
                .max(BigDecimal::compareTo);

        if (maxAmount.isPresent()) {
            BigDecimal max = maxAmount.get();
            boolean isFirstMax = true;
            BigDecimal sumAmount = BigDecimal.ZERO;

            for (Map<String, Object> branch : branchLink) {
                BigDecimal amount = (BigDecimal) branch.get("total_amount");
                if (amount.compareTo(max) == 0 && isFirstMax) {
                    isFirstMax = false;
                } else {
                    sumAmount = sumAmount.add(amount);
                }
            }

            return sumAmount;
        }

        return BigDecimal.ZERO;
    }


    /**
     * 判断能否达到升级条件
     */
    private boolean isUpgradeAchieved(List<SzVipRule> vipRules, BigDecimal totalAmount, Long parentId) {
        SzVipRule nextLevelRule = vipRules.get(1);
        BigDecimal nextLevelAccumulateMoney = nextLevelRule.getAccumulateMoney();
        log.info("用户{} 下一代理等级{}升级需要 邀请用户去掉最大分支，总消费额达到{}，当前已有{}", parentId, nextLevelRule.getVipName(), nextLevelAccumulateMoney, totalAmount);
        return totalAmount.compareTo(nextLevelAccumulateMoney) >= 0 && isPreviousLevelCountAchieved(nextLevelRule, parentId);
    }

    private boolean isPreviousLevelCountAchieved(SzVipRule nextLevelRule, Long parentId) {
        int requiredCount = nextLevelRule.getSonCount();
        int previousLevelCount = getPreviousLevelUserCount(nextLevelRule.getSonId(), parentId);
        log.info("用户{} 下一代理等级{}升级需要 邀请的本级用户数达到{}，当前已有{}",parentId, nextLevelRule.getVipName(), requiredCount, previousLevelCount);
        return previousLevelCount >= requiredCount;
    }

    private int getPreviousLevelUserCount(Long sonVipId, Long parentId) {
        return szUserMapper.getPreviousLevelUserCount(sonVipId, parentId);
    }


    /**
     * 升级VIP
     * @param parentId  那个人
     * @param id 升到哪一级
     */
    private void upgradeVip(Long parentId, Long id) {
        SzUser user = szUserMapper.selectById(parentId);
        user.setSzAgency(id);
        szUserMapper.updateById(user);

        SzVipUpgradeRecord recentRecord = szVipUpgradeRecordMapper.selectList(new LambdaQueryWrapper<SzVipUpgradeRecord>()
                .eq(SzVipUpgradeRecord::getUserId, parentId)
                .orderByDesc(SzVipUpgradeRecord::getCreateTime)).get(0);
        Long day = Duration.between(recentRecord.getCreateTime(), LocalDateTime.now()).toDays();
        recentRecord.setBeforeVip(recentRecord.getVipId());
        recentRecord.setVipId(id);
        recentRecord.setId(null);
        recentRecord.setCreateTime(LocalDateTime.now());
        recentRecord.setElapsedDay(day.intValue());
        szVipUpgradeRecordMapper.insert(recentRecord);
    }


    /**
     * 发放奖励
     */
    private void issueReward(List<Map<String, Long>> upperLevelUser, SzUser user, Long orderId) {
        Map<Long, SzVipRule> vipRules = ruleCache.getVipRules().stream().collect(Collectors.toMap(SzVipRule::getId, rule -> rule));
        SzOtherRule otherRule = ruleCache.getOtherRule();
        log.info("VIP开通成功，准备发放推荐人奖励");

        this.issueTeamReward(upperLevelUser, user, orderId, vipRules, otherRule);
        log.info("团队奖励 极差奖励 发放完毕");

        this.updateLateralBalance(upperLevelUser, user, orderId, vipRules, otherRule);
        log.info("平级奖 发放完毕");
    }

    /**
     * 发放团队奖励 + 极差奖励
     */
    private void issueTeamReward(List<Map<String, Long>> upperLevelUser, SzUser user, Long orderId, Map<Long, SzVipRule> vipRules, SzOtherRule otherRule) {
        Map<Long, Map<String, Long>> parentLevel = upperLevelUser.stream().collect(Collectors.toMap(key -> key.get("LEVEL"), Function.identity()));

        for (Map<String, Long> acceptUser : upperLevelUser) {
            SzVipRule vip = vipRules.get(acceptUser.get("vip"));

            SzUser parent = szUserMapper.selectOne(new LambdaQueryWrapper<SzUser>()
                    .eq(SzUser::getId, acceptUser.get("parent_id"))
                    .select(SzUser::getIsSignOut, SzUser::getIsFrozen, SzUser::getNickname, SzUser::getSzEnable));

            if (StringUtil.isEmpty(parent.getIsFrozen()) || "1".equals(parent.getIsFrozen())){
                log.info("发放团推奖励/极差奖励  推荐人id:{} name:{} 数字直播已被冻结，跳过发放", acceptUser.get("parent_id"), parent.getNickname());
                continue;
            }

            if (StringUtil.isEmpty(parent.getIsSignOut()) || "1".equals(parent.getIsSignOut())){
                log.info("发放团推奖励/极差奖励  推荐人id:{} name:{} 平台账号已被注销，跳过发放", acceptUser.get("parent_id"), parent.getNickname());
                continue;
            }

            if ("1".equals(parent.getDeleteFlag())){
                log.info("发放团推奖励/极差奖励  推荐人id:{} name:{} 平台账号已被管理员删除，跳过发放", acceptUser.get("parent_id"), parent.getNickname());
                continue;
            }

            if (parent.getSzEnable().equals("0")){
                log.info("发放团推奖励/极差奖励  推荐人id:{} name:{}未开通，跳过发放; 同时跳过上级所有用户的极差奖励发放", acceptUser.get("parent_id"), parent.getNickname());
                continue;
            }

            log.info("发放推荐人id:{} name:{} (代理等级{}), 和购买人{}等级关系为{}级", acceptUser.get("parent_id"), parent.getNickname(), vip.getVipName(), user.getNickname(), acceptUser.get("LEVEL"));
            if (acceptUser.get("LEVEL").equals(1L)){
                this.updateAccountBalance(upperLevelUser, acceptUser, user, orderId, vip, otherRule, "2");
            }else{
                vip.setRangeReward(this.computeExtremeBonus(parentLevel, acceptUser, user, vipRules));
                this.updateAccountBalance(upperLevelUser, acceptUser, user, orderId, vip, otherRule, "3");
            }
        }

    }


    /**
     * 计算极差奖励
     * @param parentLevel  key:Level  value:parent_id LEVEL vip
     * @param acceptUser   当前处理用户
     * @param user          购买用户
     * @param vipRules
     * @return
     */
    private BigDecimal computeExtremeBonus(Map<Long, Map<String, Long>> parentLevel, Map<String, Long> acceptUser, SzUser user, Map<Long, SzVipRule> vipRules) {
        Map<String, Long> defaultUser = parentLevel.get(1L);

        if (defaultUser.getOrDefault("vip", 0L) == 0L) {
            // 直接推荐人没有开通
            Map<String, Long> recentUsers = getRecentUsers(parentLevel);
            if (!recentUsers.isEmpty() && Objects.equals(recentUsers.get("parent_id"), acceptUser.get("parent_id"))) {
                return getRecentUserExtremeBonus(recentUsers.get("vip"), vipRules);
            }

            return getSubordinateUsersExtremeBonus(acceptUser, parentLevel, vipRules);
        }else{
            // 直接推荐人开通了
            return getSuperiorUserExtremeBonus(defaultUser, acceptUser, parentLevel, vipRules);
        }
    }


    /**
     * 获取距离直推人，最近的一个开通用户
     */
    private Map<String, Long> getRecentUsers(Map<Long, Map<String, Long>> parentLevel) {
        return parentLevel.entrySet().stream()
                .map(Map.Entry::getValue)
                .filter(userData -> userData.getOrDefault("vip", 0L) > 0L)
                .min(Comparator.comparingLong(userData -> userData.getOrDefault("LEVEL", 0L)))
                .orElse(Collections.emptyMap());
    }

    /**
     * 计算与直推人关系最近的用户的极差奖励
     * @return
     */
    private BigDecimal getRecentUserExtremeBonus(Long vipId ,Map<Long, SzVipRule> vipRules){
        SzVipRule vipRule = vipRules.get(vipId);
        SzVipRule defaultVipRule = vipRules.get(1L);
        return BigDecimalChain.chain(vipRule.getTeamReward()).sub(defaultVipRule.getTeamReward()).get();
    }

    /**
     * 直推人未开通 计算与距离最近已开通用户的极差奖励
     */
    private BigDecimal getSubordinateUsersExtremeBonus(Map<String, Long> currentUser, Map<Long, Map<String, Long>> parentLevel, Map<Long, SzVipRule> vipRules) {
        Long currentUserLevel = currentUser.get("LEVEL");
        Long currentUserVipId = currentUser.get("vip");

        Map<String, Long> subordinateUser = parentLevel.entrySet().stream()
                .map(Map.Entry::getValue)
                .filter(user -> user.get("vip") > 0L && user.get("LEVEL") < currentUserLevel)
                .max(Comparator.comparingLong(user -> user.get("LEVEL")))
                .orElse(Collections.emptyMap());

        if (subordinateUser.isEmpty() || currentUserVipId <= subordinateUser.get("vip")){
            return BigDecimal.ZERO;
        }

        SzVipRule userVip = vipRules.get(currentUserVipId);
        SzVipRule subordinateUserVip = vipRules.get(subordinateUser.get("vip"));

        return BigDecimalChain.chain(userVip.getTeamReward()).sub(subordinateUserVip.getTeamReward()).get();
    }


    /**
     * 直推人已开通，计算与距离最近已开通用户的极差奖励
     */
    private BigDecimal getSuperiorUserExtremeBonus(Map<String, Long> defaultUser, Map<String, Long> currentUser, Map<Long, Map<String, Long>> parentLevel, Map<Long, SzVipRule> vipRules) {
        Long currentUserLevel = currentUser.get("LEVEL");
        Long currentUserVipId = currentUser.get("vip");
        Long defaultUserVipId = defaultUser.get("vip");

        if (currentUserVipId <= defaultUserVipId){
            return BigDecimal.ZERO;
        }

        Map<String, Long> subordinateUser = parentLevel.entrySet().stream()
                .map(Map.Entry::getValue)
                .filter(user -> user.get("vip") > 0L && user.get("LEVEL") < currentUserLevel)
                .max(Comparator.comparingLong(user -> user.get("LEVEL")))
                .orElse(Collections.emptyMap());

        if (subordinateUser.isEmpty() || currentUserVipId <= subordinateUser.get("vip")){
            return BigDecimal.ZERO;
        }

        SzVipRule userVip = vipRules.get(currentUserVipId);
        SzVipRule subordinateUserVip = vipRules.get(subordinateUser.get("vip"));
        SzVipRule defaultUserVip = vipRules.get(defaultUserVipId);

        if (subordinateUser.get("vip") > defaultUserVipId){
            return BigDecimalChain.chain(userVip.getTeamReward()).sub(subordinateUserVip.getTeamReward()).get();
        }else{
            return BigDecimalChain.chain(userVip.getTeamReward()).sub(defaultUserVip.getTeamReward()).get();
        }
    }


    /**
     * 团队奖励  极差奖励  更新余额
     * type: 奖励类型 dmc008
     */
    private void updateAccountBalance(List<Map<String, Long>> upperLevelUser, Map<String, Long> acceptUser, SzUser user, Long orderId, SzVipRule vip, SzOtherRule otherRule, String type){
        // 计算实际获得余额
        Long userId = acceptUser.get("parent_id");
        SzUser updateUser = szUserMapper.selectById(userId);
        BigDecimal actualMoney = null;
        BigDecimal getMoney = null;
        BigDecimal deductionAmount = user.getDeductionAmount();

        switch (type) {
            case "2":
                actualMoney = BigDecimalChain.chain(vip.getTeamReward())
                        .mul(new BigDecimal("1.00").subtract(otherRule.getDonateRatio())).get();
                getMoney = vip.getTeamReward();
                updateUser.setSzTeamReward(BigDecimalChain.chain(updateUser.getSzTeamReward())
                        .add(actualMoney).get());
                updateUser.setSzWalletBalance(BigDecimalChain.chain(updateUser.getSzWalletBalance())
                        .add(actualMoney).get());
                log.info("发放团队奖励：{}元", actualMoney);
                break;

            case "3":
                actualMoney = BigDecimalChain.chain(vip.getRangeReward())
                        .mul(new BigDecimal("1.00").subtract(otherRule.getDonateRatio())).get();
                getMoney = vip.getRangeReward();
                updateUser.setSzRangeReward(BigDecimalChain.chain(updateUser.getSzRangeReward())
                        .add(actualMoney).get());
                updateUser.setSzWalletBalance(BigDecimalChain.chain(updateUser.getSzWalletBalance())
                        .add(actualMoney).get());
                log.info("发放极差奖励：{}元", actualMoney);
                break;

            case "4":
                actualMoney = BigDecimalChain.chain(vip.getLateralReward())
                        .mul(new BigDecimal("1.00").subtract(otherRule.getDonateRatio())).get();
                getMoney = vip.getLateralReward();
                updateUser.setSzLateralReward(BigDecimalChain.chain(updateUser.getSzLateralReward())
                        .add(actualMoney).get());
                updateUser.setSzWalletBalance(BigDecimalChain.chain(updateUser.getSzWalletBalance())
                        .add(actualMoney).get());
                log.info("发放平级奖励：{}元", actualMoney);
                break;

            default:
                log.error("type：{}有误",type);
        }

        if (actualMoney.compareTo(BigDecimal.ZERO) > 0){
            SzAwardRecord awardRecord = new SzAwardRecord();
            awardRecord.setBeneficiary(userId);
            awardRecord.setBuyPerson(user.getId());
            awardRecord.setOrderId(orderId);
            awardRecord.setGetTime(LocalDateTime.now());
            awardRecord.setGetMoney(getMoney);
            awardRecord.setDonateRatio(otherRule.getDonateRatio());
            awardRecord.setActualMoney(actualMoney);
            awardRecord.setType(convertFlowType(type, deductionAmount));
            szAwardRecordMapper.insert(awardRecord);

            SzWalletDetail walletDetail = new SzWalletDetail();
            walletDetail.setUserId(userId);
            walletDetail.setMoney(actualMoney);
            walletDetail.setFlowType(convertFlowType(type, deductionAmount));
            walletDetail.setOrderId(orderId);
            walletDetail.setAwardId(awardRecord.getId());
            walletDetail.setCreateTime(LocalDateTime.now());
            szWalletDetailMapper.insert(walletDetail);

            if (deductionAmount.compareTo(BigDecimal.ZERO) != 0){
                updateUser.setPendingActivationBalance(BigDecimalChain.chain(updateUser.getPendingActivationBalance())
                        .add(actualMoney).get());
            }
            szUserMapper.updateById(updateUser);

            log.info("准备发放平级奖励");
            this.countPeerRewards(upperLevelUser, acceptUser, user, orderId, vip, otherRule, type, actualMoney);
            log.info("平级奖励发放完毕");
        }
    }

    /**
     * 发放平级奖
     */
    @Deprecated
    private void updateLateralBalance(List<Map<String, Long>> upperLevelUser, SzUser user, Long orderId, Map<Long, SzVipRule> vipRules, SzOtherRule otherRule) {
        Optional<Map<String, Long>> criterion = upperLevelUser.stream()
                .filter(data -> data.get("LEVEL").equals(1L))
                .findFirst();

        List<Map<String, Long>> parentList = upperLevelUser.stream()
                .filter(data -> !data.get("LEVEL").equals(1L))
                .collect(Collectors.toList());

        criterion.ifPresent(criterionData -> {
            Long vip = criterionData.get("vip");
            if (vip != null && vip > 0L) {
                parentList.stream()
                        .filter(acceptUser -> vip.equals(acceptUser.get("vip")))
                        .findFirst()
                        .ifPresent(acceptUser -> {
                            SzUser parent = szUserMapper.selectOne(new LambdaQueryWrapper<SzUser>()
                                    .eq(SzUser::getId, acceptUser.get("parent_id"))
                                    .select(SzUser::getIsSignOut, SzUser::getIsFrozen, SzUser::getNickname));

                            log.info("发放推荐人{} {}平级奖", acceptUser.get("parent_id"), parent.getNickname());

                            if (StringUtil.isEmpty(parent.getIsFrozen()) || "1".equals(parent.getIsFrozen())){
                                log.info("发放平级奖  推荐人id:{} name:{} 数字直播已被冻结，跳过发放", acceptUser.get("parent_id"), parent.getNickname());
                            }else if (StringUtil.isEmpty(parent.getIsSignOut()) || "1".equals(parent.getIsSignOut())){
                                log.info("发放平级奖  推荐人id:{} name:{} 平台账号已被注销，跳过发放", acceptUser.get("parent_id"), parent.getNickname());
                            }else if ("1".equals(parent.getDeleteFlag())){
                                log.info("发放平级奖  推荐人id:{} name:{} 平台账号已被管理员删除，跳过发放", acceptUser.get("parent_id"), parent.getNickname());
                            } else{
                                SzVipRule vipRule = vipRules.get(acceptUser.get("vip"));
//                                this.updateAccountBalance(acceptUser, user, orderId, vipRule, otherRule, "4");
                                this.countPeerRewards(acceptUser, criterion.get(), user, orderId, vipRule, otherRule, "4");
                            }

                        });
            }
        });
    }


    /**
     * 发放平级奖
     * @param upperLevelUser  用户关系
     * @param acceptUser  奖励接收人
     * @param user  购买人
     * @param orderId  购买订单号
     * @param vip  接收人VIP等级
     * @param otherRule  其它规则
     * @param type  奖励类型dm008
     * @param acceptMoney  接收人获得奖励金额
     */
    private void countPeerRewards(List<Map<String, Long>> upperLevelUser, Map<String, Long> acceptUser, SzUser user, Long orderId, SzVipRule vip, SzOtherRule otherRule, String type, BigDecimal acceptMoney){
        List<Map<String, Long>> parentList = upperLevelUser.stream()
                .filter(data -> data.get("LEVEL") > acceptUser.get("LEVEL"))
                .collect(Collectors.toList());

        parentList.stream()
                .filter(gainUser -> acceptUser.get("vip").equals(gainUser.get("vip")))
                .findFirst()
                .ifPresent(gainUser -> {
                    SzUser parent = szUserMapper.selectOne(new LambdaQueryWrapper<SzUser>()
                            .eq(SzUser::getId, gainUser.get("parent_id"))
                            .select(SzUser::getIsSignOut, SzUser::getIsFrozen, SzUser::getNickname));

                    log.info("发放推荐人{}: {}的平级奖，奖励来源为用户{}, 获得的奖励类型为{}的奖励, 金额：{}；本次购买人{}", gainUser.get("parent_id"), parent.getNickname(), acceptUser.get("parent_id"), type, acceptMoney, user.getNickname());

                    if (StringUtil.isEmpty(parent.getIsFrozen()) || "1".equals(parent.getIsFrozen())){
                        log.info("发放平级奖  推荐人id:{} name:{} 数字直播已被冻结，跳过发放", acceptUser.get("parent_id"), parent.getNickname());
                    }else if (StringUtil.isEmpty(parent.getIsSignOut()) || "1".equals(parent.getIsSignOut())){
                        log.info("发放平级奖  推荐人id:{} name:{} 平台账号已被注销，跳过发放", acceptUser.get("parent_id"), parent.getNickname());
                    }else if ("1".equals(parent.getDeleteFlag())){
                        log.info("发放平级奖  推荐人id:{} name:{} 平台账号已被管理员删除，跳过发放", acceptUser.get("parent_id"), parent.getNickname());
                    } else{
                        this.countPeerRewards(gainUser, acceptUser, acceptMoney, user, orderId, vip, otherRule, type, "4");
                    }

                });
    }


    /**
     * 实际发放平级奖励
     * @param acceptUser 接收人
     * @param starttUser 带来人
     * @param acceptMoney 产生金额
     * @param user  购买人
     * @param orderId 订单id
     * @param vip 接收人VIP
     * @param otherRule 其它规则
     * @param acceptType 产生平级奖的类型
     * @param type 带来收益类型
     */
    private void countPeerRewards(Map<String, Long> acceptUser, Map<String, Long> starttUser, BigDecimal acceptMoney, SzUser user, Long orderId, SzVipRule vip, SzOtherRule otherRule, String acceptType, String type){
        Long userId = acceptUser.get("parent_id");

        // 接受奖励的用户
        SzUser updateUser = szUserMapper.selectById(userId);
        BigDecimal deductionAmount = user.getDeductionAmount();

        // 计算实际获得余额
        BigDecimal actualMoney = BigDecimalChain.chain(acceptMoney)
                .mul(vip.getLateralReward())
                .mul(new BigDecimal("1.00").subtract(otherRule.getDonateRatio())).get();
        log.info("计算后发放平级奖励：{}元, 产生的收益为：{}元，平级奖比例为：{}，公益基金比例为：{}", actualMoney, acceptMoney, vip.getLateralReward(), otherRule.getDonateRatio());
        log.info("计算平级奖应获得：{}", actualMoney);

        updateUser.setSzLateralReward(BigDecimalChain.chain(updateUser.getSzLateralReward())
                .add(actualMoney).get());
        updateUser.setSzWalletBalance(BigDecimalChain.chain(updateUser.getSzWalletBalance())
                .add(actualMoney).get());

        if (actualMoney.compareTo(BigDecimal.ZERO) > 0){
            SzAwardRecord awardRecord = new SzAwardRecord();
            awardRecord.setBeneficiary(userId);
            awardRecord.setBuyPerson(user.getId());
            awardRecord.setOrderId(orderId);
            awardRecord.setGetTime(LocalDateTime.now());
            awardRecord.setGetMoney(actualMoney);
            awardRecord.setDonateRatio(otherRule.getDonateRatio());
            awardRecord.setActualMoney(actualMoney);
            awardRecord.setType(convertFlowType(type, deductionAmount));
            awardRecord.setStarttUser(starttUser.get("parent_id"));
            awardRecord.setEarningType(acceptType);
            szAwardRecordMapper.insert(awardRecord);

            SzWalletDetail walletDetail = new SzWalletDetail();
            walletDetail.setUserId(userId);
            walletDetail.setMoney(actualMoney);
            walletDetail.setFlowType(convertFlowType(type, deductionAmount));
            walletDetail.setOrderId(orderId);
            walletDetail.setAwardId(awardRecord.getId());
            walletDetail.setCreateTime(LocalDateTime.now());
            szWalletDetailMapper.insert(walletDetail);

            if (deductionAmount.compareTo(BigDecimal.ZERO) != 0){
                updateUser.setPendingActivationBalance(BigDecimalChain.chain(updateUser.getPendingActivationBalance())
                        .add(actualMoney).get());
            }
            szUserMapper.updateById(updateUser);
        }

    }


    /**
     * 发放平级奖励
     * @param acceptUser  接收人
     * @param starttUser  起始人
     * @param user  购买人
     * @param orderId  订单id
     * @param vip  接收人等级
     * @param otherRule  其它规则
     */
    @Deprecated
    private void countPeerRewards(Map<String, Long> acceptUser, Map<String, Long> starttUser, SzUser user, Long orderId, SzVipRule vip, SzOtherRule otherRule, String type){
        Long userId = acceptUser.get("parent_id");
        BigDecimal allMoney = szUserMapper.countPeerRewards(starttUser.get("parent_id")); // 下级产生的所有奖励
        BigDecimal oldMoney = szUserMapper.countOldPeerRewards(userId, starttUser.get("parent_id"));// 待扣除的奖励

        SzUser updateUser = szUserMapper.selectById(userId);
        BigDecimal deductionAmount = user.getDeductionAmount();

        // 计算实际获得余额
        BigDecimal actualMoney = BigDecimalChain.chain(allMoney)
                .mul(vip.getLateralReward())
                .mul(new BigDecimal("1.00").subtract(otherRule.getDonateRatio())).get();
        log.info("计算平级奖：总收益为：{}，已产生收益为：{}", actualMoney, oldMoney);
        actualMoney = BigDecimalChain.chain(actualMoney).sub(oldMoney).get();

        BigDecimal getMoney = allMoney;
        updateUser.setSzLateralReward(BigDecimalChain.chain(updateUser.getSzLateralReward())
                .add(actualMoney).get());
        updateUser.setSzWalletBalance(BigDecimalChain.chain(updateUser.getSzWalletBalance())
                .add(actualMoney).get());
        log.info("计算后发放平级奖励：{}元, 下级总收益为：{}元，平级奖比例为：{}，公益基金比例为：{}", actualMoney, allMoney, vip.getLateralReward(), otherRule.getDonateRatio());

        if (actualMoney.compareTo(BigDecimal.ZERO) > 0){
            SzAwardRecord awardRecord = new SzAwardRecord();
            awardRecord.setBeneficiary(userId);
            awardRecord.setBuyPerson(user.getId());
            awardRecord.setOrderId(orderId);
            awardRecord.setGetTime(LocalDateTime.now());
            awardRecord.setGetMoney(getMoney);
            awardRecord.setDonateRatio(otherRule.getDonateRatio());
            awardRecord.setActualMoney(actualMoney);
            awardRecord.setType(convertFlowType(type, deductionAmount));
            awardRecord.setStarttUser(starttUser.get("parent_id"));
            szAwardRecordMapper.insert(awardRecord);

            SzWalletDetail walletDetail = new SzWalletDetail();
            walletDetail.setUserId(userId);
            walletDetail.setMoney(actualMoney);
            walletDetail.setFlowType(convertFlowType(type, deductionAmount));
            walletDetail.setOrderId(orderId);
            walletDetail.setAwardId(awardRecord.getId());
            walletDetail.setCreateTime(LocalDateTime.now());
            szWalletDetailMapper.insert(walletDetail);

            if (deductionAmount.compareTo(BigDecimal.ZERO) != 0){
                updateUser.setPendingActivationBalance(BigDecimalChain.chain(updateUser.getPendingActivationBalance())
                        .add(actualMoney).get());
            }
            szUserMapper.updateById(updateUser);
        }

    }


}
